﻿using KorbeRTR.Utility;
using KorbeRTR.Utility.HslWapper;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;

namespace KorbeRTR.Models
{
    public class OmronData
    {
        public static int D镀铜槽数 => Config.镀铜段数;

        /// <summary>
        /// 上料参数
        /// </summary>
        public class Type上料参数
        {
            /// <summary>
            /// 镀铜槽参数
            /// </summary>
            public class Type铜槽上料参数
            {
                public Type铜槽上料参数(int slot)
                {
                    var group = new VariableGroupAttribute("D", 4100);

                    int BaseAddr = 4131;
                    if (slot < 4)
                    {
                        BaseAddr = 4131 + 3 * (slot - 1);
                    }
                    else if (slot < 7)
                    {
                        BaseAddr = 4141 + 3 * (slot - 4);
                    }
                    else
                    {
                        BaseAddr = 4151 + 3 * (slot - 7);
                    }

                    Slot = slot;
                    this.C面电流 = new CurrentVariable("D", BaseAddr + 0, string.Format("铜{0}C面电流", Slot), group);
                    this.S面电流 = new CurrentVariable("D", BaseAddr + 1, string.Format("铜{0}S面电流", Slot), group);
                    this.喷流频率 = new BCDF1Uint16("D", BaseAddr + 2, string.Format("铜{0}喷流频率", Slot), group);
                }

                /// <summary>
                /// 镀铜槽号
                /// </summary>
                public int Slot { get; }

                /// <summary>
                /// A
                /// </summary>
                [VariableLog]
                [Variable]
                public readonly CurrentVariable C面电流;

                /// <summary>
                /// A
                /// </summary>
                [VariableLog]
                [Variable]
                public readonly CurrentVariable S面电流;


                /// <summary>
                /// Hz
                /// </summary>
                [VariableLog]
                [Variable]
                public readonly BCDF1Uint16 喷流频率;
            }

            /// <summary>
            /// mm/s
            /// </summary>
            [VariableLog]
            [Variable]
            public readonly BCDF2Uint16 D镀铜速度;

            /// <summary>
            /// mm
            /// </summary>
            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 K宽度;

            /// <summary>
            /// V
            /// </summary>
            [VariableLog]
            [Variable]
            public readonly BCDF2Uint16 K卡板电压;

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> L料号ID;

            [Variable]
            public readonly Type铜槽上料参数[] T铜槽;

            public Type上料参数()
            {
                var group = new VariableGroupAttribute("D", 4100);

                this.D镀铜速度 = new BCDF2Uint16("D", 4121, "镀铜速度", group);
                this.K卡板电压 = new BCDF2Uint16("D", 4122, "卡板电压", group);
                this.K宽度 = new BCDF0Uint16("D", 4123, "宽度", group);
                this.L料号ID = new Variable<UInt16>("D", 4124, "料号ID", group);

                this.T铜槽 = new Type铜槽上料参数[D镀铜槽数];
                for (int i = 0; i < this.T铜槽.Length; i++)
                {
                    this.T铜槽[i] = new Type铜槽上料参数(i + 1);
                }
            }
        }

        /// <summary>
        /// 镀铜槽状态
        /// </summary>
        public class Type镀铜槽
        {
            /// <summary>
            /// 槽号
            /// </summary>
            public int Slot { get; }

            [Posedge]
            [Variable]
            public readonly Variable<bool>[] Set喷流泵;

            [VariableLog]
            [Variable]
            public readonly Variable<bool>[] Get喷流泵;

            /// <summary>
            /// A
            /// </summary>
            [VariableLog]
            [Variable]
            public readonly CurrentVariable[] C面设定电流;

            [VariableLog]
            [Variable]
            public readonly CurrentVariable[] S面设定电流;

            [Variable]
            public readonly CurrentVariable[] C面实际电流;

            [Variable]
            public readonly CurrentVariable[] S面实际电流;


            /// <summary>
            /// Hz
            /// </summary>
            [VariableLog]
            [Variable]
            public readonly BCDF1Uint16[] 设定频率;

            /// <summary>
            /// Hz
            /// </summary>
            [VariableLog]
            [Variable]
            public readonly BCDF1Uint16[] 设定显示频率;

            /// <summary>
            /// Hz
            /// </summary>
            [Variable]
            public readonly BCDF1Uint16[] 实际频率;

            public Type镀铜槽(int slot)
            {
                Slot = slot;
                int index = Slot - 1;

                var GroupD3900 = new VariableGroupAttribute("D", 3900);
                var GroupD4400 = new VariableGroupAttribute("D", 4400);
                var GroupD4500 = new VariableGroupAttribute("D", 4500);
                var GroupC400 = new VariableGroupAttribute("C", 400);

                this.C面设定电流 = new CurrentVariable[1];
                this.C面设定电流[0] = new CurrentVariable("D", 4401 + 2 * index, string.Format("铜{0}-1C面设定电流", Slot), GroupD4400);

                this.S面设定电流 = new CurrentVariable[1];
                this.S面设定电流[0] = new CurrentVariable("D", 4402 + 2 * index, string.Format("铜{0}-1S面设定电流", Slot), GroupD4400);

                this.C面实际电流 = new CurrentVariable[1];
                this.C面实际电流[0] = new CurrentVariable("D", 4451 + 2 * index, string.Format("铜{0}-1C面实际电流", Slot), GroupD4400);

                this.S面实际电流 = new CurrentVariable[1];
                this.S面实际电流[0] = new CurrentVariable("D", 4452 + 2 * index, string.Format("铜{0}-1S面实际电流", Slot), GroupD4400);


                this.设定频率 = new BCDF1Uint16[2];
                this.设定频率[0] = new BCDF1Uint16("D", 4501 + 2 * index, string.Format("铜{0}-设定频率1", Slot), GroupD4500);
                this.设定频率[1] = new BCDF1Uint16("D", 4502 + 2 * index, string.Format("铜{0}-设定频率2", Slot), GroupD4500);

                this.设定显示频率 = new BCDF1Uint16[2];
                this.设定显示频率[0] = new BCDF1Uint16("D", 3900 + 2 * index, string.Format("铜{0}-设定频率1", Slot), GroupD3900);
                this.设定显示频率[1] = new BCDF1Uint16("D", 3901 + 2 * index, string.Format("铜{0}-设定频率2", Slot), GroupD3900);

                this.实际频率 = new BCDF1Uint16[2];
                this.实际频率[0] = new BCDF1Uint16("D", 4551 + 2 * index, string.Format("铜{0}-实际频率1", Slot), GroupD4500);
                this.实际频率[1] = new BCDF1Uint16("D", 4552 + 2 * index, string.Format("铜{0}-实际频率2", Slot), GroupD4500);

                this.Set喷流泵 = new Variable<bool>[2];
                this.Set喷流泵[0] = new Variable<bool>("C", 405, 2 * index + 0, string.Format("铜{0}-喷流泵1", Slot), GroupC400);
                this.Set喷流泵[1] = new Variable<bool>("C", 405, 2 * index + 1, string.Format("铜{0}-喷流泵2", Slot), GroupC400);

                this.Get喷流泵 = new Variable<bool>[2];
                this.Get喷流泵[0] = new Variable<bool>("C", 415, 2 * index + 0, string.Format("铜{0}-喷流泵1", Slot), GroupC400);
                this.Get喷流泵[1] = new Variable<bool>("C", 415, 2 * index + 1, string.Format("铜{0}-喷流泵2", Slot), GroupC400);
            }

            public static Type镀铜槽[] Create()
            {
                var array = new Type镀铜槽[D镀铜槽数];
                for (int i = 0; i < array.Length; i++)
                {
                    array[i] = new Type镀铜槽(i + 1);
                }
                return array;
            }
        }

        /// <summary>
        /// 温度参数
        /// </summary>
        public class TemperatureParams
        {
            public TemperatureParams(string name, int index)
            {
                string Area = "D";
                var Group = new VariableGroupAttribute("D", 4200);

                Name = name;

                int BaseAddr = 4201 + index * 10;

                设定值 = new TemperatureVariable(Area, BaseAddr + 0, string.Format("{0}设定值", name), Group);
                实际值 = new TemperatureVariable(Area, BaseAddr + 1, string.Format("{0}实际值", name), Group);
                超温 = new TemperatureVariable(Area, BaseAddr + 2, string.Format("{0}超温", name), Group);
                低温 = new TemperatureVariable(Area, BaseAddr + 3, string.Format("{0}低温", name), Group);
                正补偿 = new TemperatureVariable(Area, BaseAddr + 4, string.Format("{0}正补偿", name), Group);
                负补偿 = new TemperatureVariable(Area, BaseAddr + 5, string.Format("{0}负补偿", name), Group);
                
                运行状态 = new Variable<UInt16>(Area, BaseAddr + 9, string.Format("{0}运行状态", name), Group);

                Group = new VariableGroupAttribute("C", 400);
                this.温控开关 = new Variable<bool>("C", 402, index, string.Format("{0}温控开关", name), Group);
                this.温控开关状态 = new Variable<bool>("C", 412, index, string.Format("{0}温控开关状态", name), Group);
            }

            /// <summary>
            /// 工艺名称
            /// </summary>
            public readonly string Name;

            [VariableLog(OperationType = "温度设定")]
            [Variable]
            public readonly TemperatureVariable 设定值;

            [Variable]
            public readonly TemperatureVariable 实际值;

            [VariableLog(OperationType = "温度设定")]
            [Variable]
            public readonly TemperatureVariable 超温;

            [VariableLog(OperationType = "温度设定")]
            [Variable]
            public readonly TemperatureVariable 低温;

            [VariableLog(OperationType = "温度设定")]
            [Variable]
            public readonly TemperatureVariable 正补偿;

            [VariableLog(OperationType = "温度设定")]
            [Variable]
            public readonly TemperatureVariable 负补偿;

            [Posedge]
            [Variable]
            public readonly Variable<bool> 温控开关;

            [VariableLog]
            [Variable]
            public readonly Variable<bool> 温控开关状态;

            [Variable]
            public readonly Variable<UInt16> 运行状态;

            public bool 加热指示 => (运行状态.Value & 1) != 0;

            public bool 冷却指示 => (运行状态.Value & 2) != 0;

            public bool 错误指示 => (运行状态.Value & 4) != 0;

            public bool 停止指示 => (运行状态.Value & 0xF8) != 0;
        }

        /// <summary>
        /// 自动添加参数
        /// </summary>
        public class Type自动添加AH
        {
            public string Name { get; }

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> 开关;

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> 模式;

            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 设定;

            [Variable]
            public readonly BCDF0Uint16 实际;

            [Variable]
            public readonly BCDF0Uint32 累计;

            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 添加杯数设定;

            [Variable]
            public readonly BCDF0Uint16 添加剩余杯数;

            [Variable]
            public readonly Variable<UInt16> 状态;

            [Variable]
            public readonly Variable<UInt16> 异常;

            public Type自动添加AH(string name, int index)
            {
                Name = name;

                var group = new VariableGroupAttribute("D", 4300);

                this.开关 = new Variable<UInt16>("D", 4301 + 10 * index, string.Format("{0}-开关", Name), group);
                this.模式 = new Variable<UInt16>("D", 4302 + 10 * index, string.Format("{0}-模式", Name), group);

                this.设定 = new BCDF0Uint16("D", 4303 + 10 * index, string.Format("{0}-设定", Name), group);
                this.实际 = new BCDF0Uint16("D", 4304 + 10 * index, string.Format("{0}-实际", Name), group);
                this.累计 = new BCDF0Uint32("D", 4305 + 10 * index, string.Format("{0}-累计", Name), group);

                this.添加杯数设定 = new BCDF0Uint16("D", 4307 + 10 * index, string.Format("{0}-添加杯数设定", Name), group);
                this.添加剩余杯数 = new BCDF0Uint16("D", 4308 + 10 * index, string.Format("{0}-添加剩余杯数", Name), group);
                this.状态 = new Variable<UInt16>("D", 4309 + 10 * index, string.Format("{0}-状态", Name), group);
                this.异常 = new Variable<UInt16>("D", 4310 + 10 * index, string.Format("{0}-异常", Name), group);
            }
        }

        public class Type自动添加CRS
        {
            public string Name { get; }

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> 开关;

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> 模式;

            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 设定;

            [Variable]
            public readonly BCDF0Uint16 实际;

            [Variable]
            public readonly BCDF0Uint32 累计;

            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 添加时间设定;

            [Variable]
            public readonly BCDF0Uint16 添加剩余时间;

            [Variable]
            public readonly Variable<UInt16> 状态;

            [Variable]
            public readonly Variable<UInt16> 异常;

            public Type自动添加CRS(string name)
            {
                Name = name;

                var group = new VariableGroupAttribute("D", 4000);

                this.开关 = new Variable<UInt16>("D", 4031, string.Format("{0}-开关", Name), group);
                this.模式 = new Variable<UInt16>("D", 4032, string.Format("{0}-模式", Name), group);
                this.设定 = new BCDF0Uint16("D", 4033, string.Format("{0}-设定", Name), group);
                this.实际 = new BCDF0Uint16("D", 4034, string.Format("{0}-实际", Name), group);
                this.累计 = new BCDF0Uint32("D", 4035, string.Format("{0}-累计", Name), group);

                this.添加时间设定 = new BCDF0Uint16("D", 4037, string.Format("{0}-添加时间设定", Name), group);
                this.添加剩余时间 = new BCDF0Uint16("D", 4038, string.Format("{0}-添加剩余时间", Name), group);
                this.状态 = new Variable<UInt16>("D", 4039, string.Format("{0}-状态", Name), group);
                this.异常 = new Variable<UInt16>("D", 4040, string.Format("{0}-异常", Name), group);
            }
        }

        /// <summary>
        /// 面积自动添加
        /// </summary>
        public class Type自动添加
        {
            public string Name { get; }

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> 开关;

            [VariableLog]
            [Variable]
            public readonly Variable<UInt16> 模式;

            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 设定;

            [Variable]
            public readonly BCDF0Uint16 实际;

            [Variable]
            public readonly BCDF0Uint32 累计;

            [VariableLog]
            [Variable]
            public readonly BCDF0Uint16 添加杯数设定;

            [Variable]
            public readonly BCDF0Uint16 添加剩余杯数;


            [Variable]
            public readonly Variable<UInt16> 状态;

            [Variable]
            public readonly Variable<UInt16> 异常;

            public Type自动添加(string name, int index)
            {
                Name = name;

                var group = new VariableGroupAttribute("D", 3600);

                this.开关 = new Variable<UInt16>("D", 3600 + index, string.Format("{0}-开关", Name), group);
                this.模式 = new Variable<UInt16>("D", 3610 + index, string.Format("{0}-模式", Name), group);
                this.设定 = new BCDF0Uint16("D", 3620 + index, string.Format("{0}-设定", Name), group);
                this.实际 = new BCDF0Uint16("D", 3630 + index, string.Format("{0}-实际", Name), group);
                this.累计 = new BCDF0Uint32("D", 3640 + 2 * index, string.Format("{0}-累计", Name), group);

                this.添加杯数设定 = new BCDF0Uint16("D", -1, string.Format("{0}-添加杯数设定", Name), group);
                this.添加剩余杯数 = new BCDF0Uint16("D", -1, string.Format("{0}-添加剩余杯数", Name), group);
                this.状态 = new Variable<UInt16>("D", 3680 + index, string.Format("{0}-状态", Name), group);
                this.异常 = new Variable<UInt16>("D", 3690 + index, string.Format("{0}-异常", Name), group);
            }
        }

        /// <summary>
        /// 槽有料信号
        /// </summary>
        public class Type料号
        {
            [Variable]
            public readonly Variable<UInt16> 水洗1料号;

            [Variable]
            public readonly Variable<UInt16> 除油2料号;

            [Variable]
            public readonly Variable<UInt16> 热水洗3料号;

            [Variable]
            public readonly Variable<UInt16> 水洗4料号;

            [Variable]
            public readonly Variable<UInt16> 水洗5料号;

            [Variable]
            public readonly Variable<UInt16> 微蚀6料号;

            [Variable]
            public readonly Variable<UInt16> 水洗7料号;

            [Variable]
            public readonly Variable<UInt16> 水洗8料号;

            [Variable]
            public readonly Variable<UInt16> 酸浸9料号;

            [Variable]
            public readonly Variable<UInt16> 导电1;

            [Variable]
            public readonly Variable<UInt16> 铜槽1;

            [Variable]
            public readonly Variable<UInt16> 导电2;

            [Variable]
            public readonly Variable<UInt16> 铜槽2;

            [Variable]
            public readonly Variable<UInt16> 导电3;

            [Variable]
            public readonly Variable<UInt16> 铜槽3;

            [Variable]
            public readonly Variable<UInt16> 导电4;

            [Variable]
            public readonly Variable<UInt16> 铜槽4;

            [Variable]
            public readonly Variable<UInt16> 导电5;

            [Variable]
            public readonly Variable<UInt16> 铜槽5;

            [Variable]
            public readonly Variable<UInt16> 导电6;

            [Variable]
            public readonly Variable<UInt16> 铜槽6;

            [Variable]
            public readonly Variable<UInt16> 导电7;

            [Variable]
            public readonly Variable<UInt16> 铜槽7;

            [Variable]
            public readonly Variable<UInt16> 导电8;

            [Variable]
            public readonly Variable<UInt16> 铜槽8;

            [Variable]
            public readonly Variable<UInt16> 导电9;

            [Variable]
            public readonly Variable<UInt16> 水洗11料号;

            [Variable]
            public readonly Variable<UInt16> 酸洗12;

            [Variable]
            public readonly Variable<UInt16> 水洗13料号;

            [Variable]
            public readonly Variable<UInt16> 水洗14料号;

            [Variable]
            public readonly Variable<UInt16> 抗氧化15;

            [Variable]
            public readonly Variable<UInt16> 水洗16料号;

            [Variable]
            public readonly Variable<UInt16> 水洗17料号;

            [Variable]
            public readonly Variable<UInt16> 水洗18料号;

            [Variable]
            public readonly Variable<UInt16> 吹干烘干19;


            public Type料号()
            {
                var group = new VariableGroupAttribute("D", 4000);
                int tmp = 4051;
                水洗1料号 = new Variable<UInt16>("D", tmp++, "水洗1料号", group);
                除油2料号 = new Variable<UInt16>("D", tmp++, "除油2料号", group);
                热水洗3料号 = new Variable<UInt16>("D", tmp++, "热水洗3料号", group);
                水洗4料号 = new Variable<UInt16>("D", tmp++, "水洗4料号", group);
                水洗5料号 = new Variable<UInt16>("D", tmp++, "水洗5料号", group);
                微蚀6料号 = new Variable<UInt16>("D", tmp++, "微蚀6料号", group);
                水洗7料号 = new Variable<UInt16>("D", tmp++, "水洗7料号", group);
                水洗8料号 = new Variable<UInt16>("D", tmp++, "水洗8料号", group);
                酸浸9料号 = new Variable<UInt16>("D", tmp++, "酸浸9料号", group);

                导电1 = new Variable<UInt16>("D", tmp++, "导电1", group);
                铜槽1 = new Variable<UInt16>("D", tmp++, "铜槽1", group);

                导电2 = new Variable<UInt16>("D", tmp++, "导电2", group);
                铜槽2 = new Variable<UInt16>("D", tmp++, "铜槽2", group);

                导电3 = new Variable<UInt16>("D", tmp++, "导电3", group);
                铜槽3 = new Variable<UInt16>("D", tmp++, "铜槽3", group);

                导电4 = new Variable<UInt16>("D", tmp++, "导电4", group);
                铜槽4 = new Variable<UInt16>("D", tmp++, "铜槽4", group);

                导电5 = new Variable<UInt16>("D", tmp++, "导电5", group);
                铜槽5 = new Variable<UInt16>("D", tmp++, "铜槽5", group);

                导电6 = new Variable<UInt16>("D", tmp++, "导电6", group);
                铜槽6 = new Variable<UInt16>("D", tmp++, "铜槽6", group);

                导电7 = new Variable<UInt16>("D", tmp++, "导电7", group);
                铜槽7 = new Variable<UInt16>("D", tmp++, "铜槽7", group);

                导电8 = new Variable<UInt16>("D", tmp++, "导电8", group);
                铜槽8 = new Variable<UInt16>("D", tmp++, "铜槽8", group);

                导电9 = new Variable<UInt16>("D", tmp++, "导电9", group);


                水洗11料号 = new Variable<UInt16>("D", tmp++, "水洗11料号", group);
                酸洗12 = new Variable<UInt16>("D", tmp++, "酸洗12", group);
                水洗13料号 = new Variable<UInt16>("D", tmp++, "水洗13料号", group);
                水洗14料号 = new Variable<UInt16>("D", tmp++, "水洗14料号", group);
                抗氧化15 = new Variable<UInt16>("D", tmp++, "抗氧化15", group);
                水洗16料号 = new Variable<UInt16>("D", tmp++, "水洗16料号", group);
                水洗17料号 = new Variable<UInt16>("D", tmp++, "水洗17料号", group);
                水洗18料号 = new Variable<UInt16>("D", tmp++, "水洗18料号", group);
                吹干烘干19 = new Variable<UInt16>("D", tmp++, "吹干烘干19", group);

            }
        }

        /// <summary>
        /// 泵浦自动开关
        /// </summary>
        public class Type自动开关
        {
            public class TypeOnOFF
            {
                public string Name { get; }

                [VariableLog]
                [Variable]
                public readonly Variable<bool> 自动开;

                [VariableLog]
                [Variable]
                public readonly Variable<bool> 自动关;

                public TypeOnOFF(string name, int addr_on, int addr_off, int sub_addr)
                {
                    Name = name;

                    var group = new VariableGroupAttribute("D", 3258);

                    自动开 = new Variable<bool>("D", addr_on, sub_addr, name + "-自动开", group);
                    自动关 = new Variable<bool>("D", addr_off, sub_addr, name + "-自动关", group);
                }
            }

            [Variable]
            public readonly TypeOnOFF CY除油 = new TypeOnOFF("除油", 3258, 3261, 0);

            [Variable]
            public readonly TypeOnOFF RS热水洗 = new TypeOnOFF("热水洗", 3258, 3261, 1);

            [Variable]
            public readonly TypeOnOFF SX水洗1 = new TypeOnOFF("水洗1", 3258, 3261, 2);

            [Variable]
            public readonly TypeOnOFF SX水洗2 = new TypeOnOFF("水洗2", 3258, 3261, 3);

            [Variable]
            public readonly TypeOnOFF WS微蚀 = new TypeOnOFF("微蚀", 3258, 3261, 4);

            [Variable]
            public readonly TypeOnOFF SX水洗3 = new TypeOnOFF("水洗3", 3258, 3261, 5);

            [Variable]
            public readonly TypeOnOFF SX水洗4 = new TypeOnOFF("水洗4", 3258, 3261, 6);

            [Variable]
            public readonly TypeOnOFF YJ预浸 = new TypeOnOFF("预浸", 3258, 3261, 7);

            [Variable]
            public readonly TypeOnOFF SX水洗5 = new TypeOnOFF("水洗5", 3258, 3261, 8);

            [Variable]
            public readonly TypeOnOFF SX水洗6 = new TypeOnOFF("水洗6", 3258, 3261, 9);

            [Variable]
            public readonly TypeOnOFF SX水洗7 = new TypeOnOFF("水洗7", 3258, 3261, 10);

            [Variable]
            public readonly TypeOnOFF ZL整流机冷却 = new TypeOnOFF("整流机冷却", 3258, 3261, 11);

            [Variable]
            public readonly TypeOnOFF XG硝挂 = new TypeOnOFF("硝挂", 3258, 3261, 12);

            [Variable]
            public readonly TypeOnOFF XG硝挂后水洗1 = new TypeOnOFF("硝挂后水洗1", 3258, 3261, 13);

            [Variable]
            public readonly TypeOnOFF XG硝挂后水洗2 = new TypeOnOFF("硝挂后水洗2", 3258, 3261, 14);

            [Variable]
            public readonly TypeOnOFF SJR水加热循环泵 = new TypeOnOFF("水加热循环泵", 3258, 3261, 15);

            [Variable]
            public readonly TypeOnOFF JT夹头吹干风车 = new TypeOnOFF("夹头吹干风车", 3259, 3262, 0);

            [Variable]
            public readonly TypeOnOFF[] P喷流泵1;

            [Variable]
            public readonly TypeOnOFF[] P喷流泵2;

            public Type自动开关()
            {
                P喷流泵1 = new TypeOnOFF[D镀铜槽数];
                for (int i = 0; i < P喷流泵1.Length; i++)
                {
                    P喷流泵1[i] = new TypeOnOFF(string.Format("铜{0}#喷流泵1", i + 1), 3259, 3262, 2 * i + 1);
                }

                P喷流泵2 = new TypeOnOFF[D镀铜槽数];
                for (int i = 0; i < P喷流泵2.Length; i++)
                {
                    P喷流泵2[i] = new TypeOnOFF(string.Format("铜{0}#喷流泵2", i + 1), 3259, 3262, 2 * i + 2);
                }
            }
        }

        public class Type水洗压力
        {
            public class Type槽水洗压力
            {
                [Variable]
                public readonly BCDF2Uint16[] 压力值;

                [VariableLog]
                [Variable]
                public readonly BCDF2Uint16[] 上限;

                [VariableLog]
                [Variable]
                public readonly BCDF2Uint16[] 下限;

                public Type槽水洗压力(string Name, int BaseAddr)
                {
                    var group = new VariableGroupAttribute("D", 4700);

                    压力值 = new BCDF2Uint16[2];
                    压力值[0] = new BCDF2Uint16("D", BaseAddr+0, string.Format("{0}水洗压力1", Name), group);
                    压力值[1] = new BCDF2Uint16("D", BaseAddr+1, string.Format("{0}水洗压力2", Name), group);

                    上限 = new BCDF2Uint16[2];
                    上限[0] = new BCDF2Uint16("D", BaseAddr + 30, string.Format("{0}水洗压力1上限", Name), group);
                    上限[1] = new BCDF2Uint16("D", BaseAddr + 31, string.Format("{0}水洗压力2上限", Name), group);

                    下限 = new BCDF2Uint16[2];
                    下限[0] = new BCDF2Uint16("D", BaseAddr + 60, string.Format("{0}水洗压力1下限", Name), group);
                    下限[1] = new BCDF2Uint16("D", BaseAddr + 61, string.Format("{0}水洗压力2下限", Name), group);
                }
            }

            [Variable]
            public readonly Type槽水洗压力 No1水洗压力 = new Type槽水洗压力("1#", 4701);

            [Variable]
            public readonly Type槽水洗压力 No4水洗压力 = new Type槽水洗压力("4#", 4703);

            [Variable]
            public readonly Type槽水洗压力 No5水洗压力 = new Type槽水洗压力("5#", 4705);

            [Variable]
            public readonly Type槽水洗压力 No7水洗压力 = new Type槽水洗压力("7#", 4707);

            [Variable]
            public readonly Type槽水洗压力 No8水洗压力 = new Type槽水洗压力("8#", 4709);

            [Variable]
            public readonly Type槽水洗压力 No10水洗压力 = new Type槽水洗压力("10#", 4711);

            [Variable]
            public readonly Type槽水洗压力 No11水洗压力 = new Type槽水洗压力("11#", 4713);

            [Variable]
            public readonly Type槽水洗压力 No13水洗压力 = new Type槽水洗压力("13#", 4715);

            [Variable]
            public readonly Type槽水洗压力 No14水洗压力 = new Type槽水洗压力("14#", 4717);

            [Variable]
            public readonly Type槽水洗压力 No15水洗压力 = new Type槽水洗压力("15#", 4719);

            [Variable]
            public readonly Type槽水洗压力 No16水洗压力 = new Type槽水洗压力("16#", 4721);

            [Variable]
            public readonly Type槽水洗压力 No17水洗压力 = new Type槽水洗压力("17#", 4723);

            [Variable]
            public readonly Type槽水洗压力 No18水洗压力 = new Type槽水洗压力("18#", 4725);

            [VariableGroup("D", 4600)]
            public readonly BCDF1Uint16 除油2流量 = new BCDF1Uint16("D", 4601, "除油2流量");

            [VariableGroup("D", 4600)]
            public readonly BCDF1Uint16 水洗3流量 = new BCDF1Uint16("D", 4602, "水洗3流量");

            [VariableGroup("D", 4600)]
            public readonly BCDF1Uint16 微蚀6流量 = new BCDF1Uint16("D", 4603, "微蚀6流量");

            [VariableGroup("D", 4600)]
            public readonly BCDF1Uint16 预浸9流量 = new BCDF1Uint16("D", 4604, "预浸9流量");

            [VariableGroup("D", 4600)]
            public readonly BCDF1Uint16 酸洗12流量 = new BCDF1Uint16("D", 4605, "酸洗12流量");
        }

        public class Type报警
        {
            [Variable]
            public Variable<bool>[] AlarmSet;

            public Type报警()
            {
                int start = 850;
                int end = 905;
                int N = (end - start) * 16;
                AlarmSet = new Variable<bool>[N];

                var group = new VariableGroupAttribute("C", start);
                int index = 0;
                for(int addr = start; addr<end; addr++)
                {
                    for(int sub_addr=0; sub_addr<16; sub_addr++)
                    {
                        AlarmSet[index++] = new Variable<bool>("C", addr, sub_addr, group);
                    }
                }
            }
        }

        #region 变量定义

        #region 上料参数
        [Variable]
        public readonly Type上料参数 SL上料参数 = new Type上料参数();

        [VariableGroup("D", 3200)]
        public readonly BCDF0Uint16 SL上料片数 = new BCDF0Uint16("D", 3253, "上料片数");

        [VariableGroup("D", 3200)]
        public readonly BCDF0Uint16 XL下料片数 = new BCDF0Uint16("D", 3254, "下料片数");
        #endregion

        #region 镀铜槽状态
        [Variable]
        public readonly Type镀铜槽[] D镀铜槽状态 = Type镀铜槽.Create();
        #endregion

        #region 温度参数
        [Variable]
        public readonly TemperatureParams CY除油温度 = new TemperatureParams("除油温度", 0);

        [Variable]
        public readonly TemperatureParams RS热水洗温度 = new TemperatureParams("热水洗温度", 1);

        [Variable]
        public readonly TemperatureParams ZL整流机冷却温度 = new TemperatureParams("整流机冷却温度", 2);

        [Variable]
        public readonly TemperatureParams SX酸洗槽温度 = new TemperatureParams("酸洗槽温度", 3);

        [Variable]
        public readonly TemperatureParams DT镀铜温度 = new TemperatureParams("镀铜温度", 4);

        [Variable]
        public readonly TemperatureParams WS微蚀温度 = new TemperatureParams("微蚀温度", 5);


        [Variable]
        public readonly TemperatureParams RS热水槽温度 = new TemperatureParams("热水槽温度", 6);

        [Variable]
        public readonly TemperatureParams HG烘干加热温度 = new TemperatureParams("烘干加热温度", 7);

        [Variable]
        public readonly TemperatureParams SJ酸浸温度 = new TemperatureParams("酸浸温度", 8);

        [Variable]
        public readonly TemperatureParams KYH抗氧化槽温度 = new TemperatureParams("抗氧化槽温度", 9);


        //[Variable]
        //public readonly TemperatureVariable RS热水温度 = new TemperatureVariable("D", 4297, "热水温度", new VariableGroupAttribute("D", 4200));
        #endregion

        #region 自动添加设定
        [Variable]
        public readonly Type自动添加AH P平整剂 = new Type自动添加AH("平整剂", 0);

        [Variable]
        public readonly Type自动添加AH G光泽剂 = new Type自动添加AH("光泽剂", 1);

        [Variable]
        public readonly Type自动添加AH S湿润剂 = new Type自动添加AH("湿润剂", 2);

        [Variable]
        public readonly Type自动添加AH SXQJ酸性清洁 = new Type自动添加AH("酸性清洁", 3);


        [Variable]
        public readonly Type自动添加AH W微蚀 = new Type自动添加AH("微蚀", 4);

        [Variable]
        public readonly Type自动添加AH SJ酸浸 = new Type自动添加AH("酸浸 ", 5);

        [Variable]
        public readonly Type自动添加AH SX酸洗 = new Type自动添加AH("酸洗", 6);

        [Variable]
        public readonly Type自动添加AH K抗氧化 = new Type自动添加AH("抗氧化", 7);

        [Variable]
        public readonly Type自动添加AH TF铜粉添加 = new Type自动添加AH("铜粉添加", 9);

        #endregion

        #region 料号
        [Variable]
        public readonly Type料号 LH料号 = new Type料号();

        public BCDF2Uint16 SD设定线速 => this.SL上料参数.D镀铜速度;

        /// <summary>
        /// 0.01mm/s
        /// </summary>
        [VariableGroup("D", 4000)]
        public readonly BCDF2Uint16 SJ实际线速 = new BCDF2Uint16("D", 4042, "实际线速");

        [VariableGroup("D", 4000)]
        public readonly Variable<bool> Flag允许切换料号 = new Variable<bool>("D", 4004, 0, "允许切换料号");

        [VariableGroup("D", 4000)]
        public readonly Variable<bool> Flag允许切换线速 = new Variable<bool>("D", 4004, 1, "允许切换线速");

        [VariableGroup("D", 4100)]
        public readonly Variable<UInt16> ZZ正在卷入料号ID = new Variable<UInt16>("D", 4111, "正在卷入料号ID");
        [VariableGroup("D", 4100)]
        public readonly Variable<UInt16> JR卷入料号ID = new Variable<UInt16>("D", 4112, "卷入料号ID");
        [VariableGroup("D", 4100)]
        public readonly Variable<UInt16> JC卷出料号ID = new Variable<UInt16>("D", 4113, "卷出料号ID");

        /// <summary>
        /// true 上轴, false 下轴
        /// </summary>
        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> RL入料上下轴选择 = new Variable<bool>("C", 410, 0, "入料上下选择");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> RL入料上下轴指示 = new Variable<bool>("C", 420, 0, "入料上下轴指示");

        /// <summary>
        /// true 上轴, false 下轴
        /// </summary>
        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> CL出料上下轴选择 = new Variable<bool>("C", 410, 1, "出料上下选择");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> CL出料上下轴指示 = new Variable<bool>("C", 420, 1, "出料上下轴指示");
        #endregion

        #region 料卷参数
        /// <summary>
        /// m
        /// </summary>
        [VariableLog]
        [VariableGroup("D", 4000)]
        public readonly BCDF0Uint16 LJ料卷长度设定 = new BCDF0Uint16("D", 4031, "料卷长度设定");

        /// <summary>
        /// mm
        /// </summary>
        [VariableLog]
        [VariableGroup("D", 4000)]
        public readonly BCDF0Uint16 SY剩余报警长度设定 = new BCDF0Uint16("D", 4032, "剩余报警长度设定");

        /// <summary>
        /// m
        /// </summary>
        [VariableLog]
        [VariableGroup("D", 4000)]
        public readonly BCDF0Uint16 SJ实际卷入长度显示 = new BCDF0Uint16("D", 4041, "实际卷入长度显示");
        #endregion

        #region 设备参数
        /// <summary>
        /// 秒
        /// </summary>
        [VariableLog]
        [VariableGroup("D", 4000)]
        public readonly BCDF0Uint16 BH保护电流时间 = new BCDF0Uint16("D", 4001, "保护电流时间");

        /// <summary>
        /// x %
        /// </summary>
        [VariableLog]
        [VariableGroup("D", 4000)]
        public readonly BCDF0Uint16 BH保护电流百分比 = new BCDF0Uint16("D", 4002, "保护电流百分比");

        [VariableLog]
        [VariableGroup("D", 4000)]
        public readonly BCDF0Uint16 BH保护电流下降爬升时间 = new BCDF0Uint16("D", 4003, "保护电流百分比");
        #endregion

        #region 泵浦自动开关
        [Variable]
        public Type自动开关 Z自动开关 = new Type自动开关();
        #endregion

        #region 产线控制、状态
        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetZD自动启动 = new Variable<bool>("C", 401, 0, "自动启动");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetZD自动启动 = new Variable<bool>("C", 411, 0, "自动启动");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetZD自动停止 = new Variable<bool>("C", 401, 1, "自动停止");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetZD自动停止 = new Variable<bool>("C", 411, 1, "自动停止");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetJY静音 = new Variable<bool>("C", 401, 2, "静音");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetYC异常复归 = new Variable<bool>("C", 401, 3, "异常复归");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetZB周边泵自动启动 = new Variable<bool>("C", 401, 5, "周边泵自动启动");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetZB周边泵自动启动 = new Variable<bool>("C", 411, 5, "周边泵自动启动");

        //[Posedge]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> SetSSF市水阀 = new Variable<bool>("C", 804, 3, "市水阀");

        //[VariableLog]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> GetSSF市水阀 = new Variable<bool>("C", 814, 3, "市水阀");

        //[Posedge]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> SetCS传送启动 = new Variable<bool>("C", 804, 4, "传送启动");

        //[VariableLog]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> GetCS传送启动 = new Variable<bool>("C", 814, 4, "传送启动");

        //[Posedge]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> SetCS传送停止 = new Variable<bool>("C", 804, 5, "传送停止");

        //[VariableLog]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> GetCS传送停止 = new Variable<bool>("C", 814, 5, "传送停止");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetJN节能模式 = new Variable<bool>("C", 401, 7, "节能模式");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetJN节能模式 = new Variable<bool>("C", 411, 7, "节能模式");

        //        [VariableLog]
        //        [VariableGroup("C", 800)]
        public readonly Variable<bool> WS维修保养开关 = new Variable<bool>("C", 804, 11, "维修保养开关");

//        [VariableGroup("D", 3250)]
        public readonly Variable<UInt16> WS维修保养开关状态 = new Variable<UInt16>("D", 3255, "维修保养开关状态");

        //[VariableLog]
        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> GetMES在线 = new Variable<bool>("C", -1, 6, "MES在线");

        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> Get上料开夹开到位 = new Variable<bool>("C", 815, 10, "上料开夹开到位");

        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> Get上料开夹闭到位 = new Variable<bool>("C", 815, 11, "上料开夹闭到位");

        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> Get上料开夹挡板开到位 = new Variable<bool>("C", 815, 12, "上料开夹挡板开到位");

        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> Get上料开夹挡板回到位 = new Variable<bool>("C", 815, 13, "上料开夹挡板回到位");

        //[VariableGroup("C", 800)]
        //public readonly Variable<bool> GetJQR机器人状态 = new Variable<bool>("C", 815, 14, "机器人状态");


        [VariableGroup("D", 4000)]
        public readonly Variable<UInt32> DB电表1 = new Variable<UInt32>("D", 4044, "电表1");

        public double DB电表 => DB电表1.Value;

        [VariableGroup("D", 4000)]
        public readonly Variable<UInt32> SB水表1_1 = new Variable<UInt32>("D", 4048, "水表1-1");

        //[VariableGroup("D", 3200)]
        //public readonly Variable<UInt16> SB水表1_2 = new Variable<UInt16>("D", 3211, "水表1-2");

        [VariableGroup("D", 4000)]
        public readonly Variable<UInt32> SB水表2_1 = new Variable<UInt32>("D", 4046, "水表2-1");

        //[VariableGroup("D", 3200)]
        //public readonly Variable<UInt16> SB水表2_2 = new Variable<UInt16>("D", 3213, "水表2-2");

        /// <summary>
        /// m^3 纯水
        /// </summary>
        public double SB水表1 => SB水表1_1.Value / 1000.0;

        /// <summary>
        /// m^3 市水
        /// </summary>
        public double SB水表2 => SB水表2_1.Value / 1000.0;
        #endregion

        #region 泵浦控制
        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetGL隔离水洗 = new Variable<bool>("C", 403, 0, "隔离水洗");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetGL隔离水洗 = new Variable<bool>("C", 413, 0, "隔离水洗");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetCY除油循环 = new Variable<bool>("C", 403, 1, "除油循环");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetCY除油循环 = new Variable<bool>("C", 413, 1, "除油循环");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetCY除油喷淋 = new Variable<bool>("C", 403, 2, "除油喷淋");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetCY除油喷淋 = new Variable<bool>("C", 413, 2, "除油喷淋");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRS热水洗循环 = new Variable<bool>("C", 403, 3, "热水洗循环");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRS热水洗循环 = new Variable<bool>("C", 413, 3, "热水洗循环");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRS热水洗喷淋 = new Variable<bool>("C", 403, 4, "热水洗喷淋");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRS热水洗喷淋 = new Variable<bool>("C", 413, 4, "热水洗喷淋");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗1 = new Variable<bool>("C", 403, 5, "水洗1");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗1 = new Variable<bool>("C", 413, 5, "水洗1");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗2 = new Variable<bool>("C", 403, 6, "水洗2");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗2 = new Variable<bool>("C", 413, 6, "水洗2");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetWS微蚀循环 = new Variable<bool>("C", 403, 7, "微蚀循环");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetWS微蚀循环 = new Variable<bool>("C", 413, 7, "微蚀循环");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetWS微蚀喷淋 = new Variable<bool>("C", 403, 8, "微蚀喷淋");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetWS微蚀喷淋 = new Variable<bool>("C", 413, 8, "微蚀喷淋");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗3 = new Variable<bool>("C", 403, 9, "水洗3");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗3 = new Variable<bool>("C", 413, 9, "水洗3");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗4 = new Variable<bool>("C", 403, 10, "水洗4");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗4 = new Variable<bool>("C", 413, 10, "水洗4");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSJ酸浸循环 = new Variable<bool>("C", 403, 11, "酸浸循环");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSJ酸浸循环 = new Variable<bool>("C", 413, 11, "酸浸循环");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSJ酸浸喷淋 = new Variable<bool>("C", 403, 12, "酸浸喷淋");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSJ酸浸喷淋 = new Variable<bool>("C", 413, 12, "酸浸喷淋");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetDD导电1段泵 = new Variable<bool>("C", 403, 13, "导电1段泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetDD导电1段泵 = new Variable<bool>("C", 413, 13, "导电1段泵");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetDD导电2段泵 = new Variable<bool>("C", 403, 14, "导电2段泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetDD导电2段泵 = new Variable<bool>("C", 413, 14, "导电2段泵");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetDD导电3段泵 = new Variable<bool>("C", 403, 15, "导电3段泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetDD导电3段泵 = new Variable<bool>("C", 413, 15, "导电3段泵");


        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetDD导电4段泵 = new Variable<bool>("C", 404, 0, "导电4段泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetDD导电4段泵 = new Variable<bool>("C", 414, 0, "导电4段泵");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗5 = new Variable<bool>("C", 404, 1, "水洗5");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗5 = new Variable<bool>("C", 414, 1, "水洗5");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗6 = new Variable<bool>("C", 404, 2, "水洗6");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗6 = new Variable<bool>("C", 414, 2, "水洗6");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX酸洗循环 = new Variable<bool>("C", 404, 3, "酸洗循环");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX酸洗循环 = new Variable<bool>("C", 414, 3, "酸洗循环");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX酸洗喷淋 = new Variable<bool>("C", 404, 4, "酸洗喷淋");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX酸洗喷淋 = new Variable<bool>("C", 414, 4, "酸洗喷淋");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗7 = new Variable<bool>("C", 404, 5, "水洗7");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗7 = new Variable<bool>("C", 414, 5, "水洗7");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗8 = new Variable<bool>("C", 404, 6, "水洗8");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗8 = new Variable<bool>("C", 414, 6, "水洗8");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetKYH抗氧化 = new Variable<bool>("C", 404, 7, "抗氧化泵浦");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetKYH抗氧化 = new Variable<bool>("C", 414, 7, "抗氧化泵浦");

     
        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗9 = new Variable<bool>("C", 404, 8, "水洗9");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗9 = new Variable<bool>("C", 414, 8, "水洗9");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗10 = new Variable<bool>("C", 404, 9, "水洗10");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗10 = new Variable<bool>("C", 414, 9, "水洗10");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗11 = new Variable<bool>("C", 404, 10, "水洗11");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗11 = new Variable<bool>("C", 414, 10, "水洗11");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetTC铜槽循环泵1 = new Variable<bool>("C", 404, 12, "铜槽循环泵1");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetTC铜槽循环泵1 = new Variable<bool>("C", 414, 12, "铜槽循环泵1");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetTC铜槽循环泵2 = new Variable<bool>("C", 404, 13, "铜槽循环泵2");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetTC铜槽循环泵2 = new Variable<bool>("C", 414, 13, "铜槽循环泵2");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSJR水加热循环泵 = new Variable<bool>("C", 408, 1, "水加热循环泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSJR水加热循环泵 = new Variable<bool>("C", 418, 1, "水加热循环泵");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetZLJ整流机冷却泵 = new Variable<bool>("C", 408, 2, "整流机冷却泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetZLJ整流机冷却泵 = new Variable<bool>("C", 418, 2, "整流机冷却泵");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetDQ打气开关 = new Variable<bool>("C", 408, 3, "打气开关");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetDQ打气开关 = new Variable<bool>("C", 418, 3, "打气开关");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetLF冷风吹干风机1 = new Variable<bool>("C", 402, 10, "冷风吹干风机1");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetLF冷风吹干风机1 = new Variable<bool>("C", 412, 10, "冷风吹干风机1");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetLF冷风吹干风机2 = new Variable<bool>("C", 402, 11, "冷风吹干风机2");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRF冷风吹干风机2 = new Variable<bool>("C", 412, 11, "冷风吹干风机2");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRF热风吹干风机1 = new Variable<bool>("C", 402, 12, "热风吹干风机1");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRF热风吹干风机1 = new Variable<bool>("C", 412, 12, "热风吹干风机1");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRF热风吹干风机2 = new Variable<bool>("C", 402, 13, "热风吹干风机2");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRF热风吹干风机2 = new Variable<bool>("C", 412, 13, "热风吹干风机2");

 
        #endregion

        #region 温度、电磁阀、补水控制
        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetGL隔离水洗补水阀 = new Variable<bool>("C", 407, 0, "隔离水洗补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetGL隔离水洗补水阀 = new Variable<bool>("C", 417, 0, "隔离水洗补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRS热水洗补水阀 = new Variable<bool>("C", 407, 1, "热水洗补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRS热水洗补水阀 = new Variable<bool>("C", 417, 1, "热水洗补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗2补水阀 = new Variable<bool>("C", 407, 2, "水洗2补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗2补水阀 = new Variable<bool>("C", 417, 2, "水洗2补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗4补水阀 = new Variable<bool>("C", 407, 3, "水洗4补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗4补水阀 = new Variable<bool>("C", 417, 3, "水洗4补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗6补水阀 = new Variable<bool>("C", 407, 4, "水洗6补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗6补水阀 = new Variable<bool>("C", 417, 4, "水洗6补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗9补水阀 = new Variable<bool>("C", 407, 5, "水洗9补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗9补水阀 = new Variable<bool>("C", 417, 5, "水洗9补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSX水洗10补水阀 = new Variable<bool>("C", 407, 6, "水洗10补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSX水洗10补水阀 = new Variable<bool>("C", 417, 6, "水洗10补水阀");

        //[VariableLog]
        //[VariableGroup("D", 4600)]
        //public readonly Variable<UInt16> GetSX水洗10补水阀 = new Variable<UInt16>("D", 4630, "水洗10补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetZLJ整流机副槽补水阀 = new Variable<bool>("C", 407, 7, "整流机副槽补水阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetZLJ整流机副槽补水阀 = new Variable<bool>("C", 417, 7, "整流机副槽补水阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Set_1_导电滚轮副槽补水阀 = new Variable<bool>("C", 407, 8, "1#导电补水电磁阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Get_1_导电滚轮副槽补水阀 = new Variable<bool>("C", 417, 8, "1#导电补水电磁阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Set_2_导电滚轮副槽补水阀 = new Variable<bool>("C", 407, 9, "2#导电补水电磁阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Get_2_导电滚轮副槽补水阀 = new Variable<bool>("C", 417, 9, "2#导电补水电磁阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Set_3_导电滚轮副槽补水阀 = new Variable<bool>("C", 407, 10, "3#导电补水电磁阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Get_3_导电滚轮副槽补水阀 = new Variable<bool>("C", 417, 10, "3#导电补水电磁阀");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Set_4_导电滚轮副槽补水阀 = new Variable<bool>("C", 407, 11, "4#导电补水电磁阀");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> Get_4_导电滚轮副槽补水阀 = new Variable<bool>("C", 417, 11, "4#导电补水电磁阀");

        //[Posedge]
        //[VariableGroup("C", 400)]
        //public readonly Variable<bool> SetSX水洗10补水阀 = new Variable<bool>("C", 407, 8, "水洗10补水阀");

        //[VariableLog]
        //[VariableGroup("C", 400)]
        //public readonly Variable<bool> GetSX水洗10补水阀 = new Variable<bool>("C", 417, 8, "水洗10补水阀");
        #endregion

        #region 其他开关
        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRTC溶铜槽打入循环泵浦开关 = new Variable<bool>("C", 406, 0, "溶铜槽打入循环泵浦开关");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRTC溶铜槽打入循环泵浦开关 = new Variable<bool>("C", 416, 0, "溶铜槽打入循环泵浦开关");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetCRS搅拌开关 = new Variable<bool>("C", 406, 1, "CRS搅拌开关");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetCRS搅拌开关 = new Variable<bool>("C", 416, 1, "CRS搅拌开关");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetTF铜粉喂料开关 = new Variable<bool>("C", 406, 3, "铜粉喂料开关");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetTF铜粉喂料开关 = new Variable<bool>("C", 416, 3, "铜粉喂料开关");


        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetRTC溶铜槽打出循环泵浦开关 = new Variable<bool>("C", 406, 5, "溶铜槽打出循环泵浦开关");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetRTC溶铜槽打出循环泵浦开关 = new Variable<bool>("C", 416, 5, "溶铜槽打出循环泵浦开关");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetWS微蚀搅拌开关 = new Variable<bool>("C", 406, 12, "微蚀搅拌开关");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetWS微蚀搅拌开关 = new Variable<bool>("C", 416, 12, "微蚀搅拌开关");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetWS微蚀溶解槽泵 = new Variable<bool>("C", 406, 13, "微蚀溶解槽泵");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetWS微蚀溶解槽泵 = new Variable<bool>("C", 416, 13, "微蚀溶解槽泵");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetQW前微蚀打入后微蚀桶 = new Variable<bool>("C", 408, 4, "前微蚀打入后微蚀桶");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetQW前微蚀打入后微蚀桶 = new Variable<bool>("C", 418, 4, "前微蚀打入后微蚀桶");


        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetSS上视窗检知= new Variable<bool>("C", 401, 8, "上视窗检知");

        [VariableLog]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetSS上视窗检知 = new Variable<bool>("C", 411, 8, "上视窗检知");

        [Posedge]
        [VariableGroup("C", 400)]
        public readonly Variable<bool> SetXTF吸铜粉开关 = new Variable<bool>("C", 406, 15, "吸铜粉开关");
        [VariableLog]

        [VariableGroup("C", 400)]
        public readonly Variable<bool> GetXTF吸铜粉开关 = new Variable<bool>("C", 416, 15, "吸铜粉开关");


        [VariableLog]
        [VariableGroup("D", 600)]
        public readonly BCDF1Uint16 TF铜粉吸时间 = new BCDF1Uint16("D", 640, "铜粉吸时间");

        [VariableLog]
        [VariableGroup("D", 600)]
        public readonly BCDF1Uint16 TF铜粉停吸时间 = new BCDF1Uint16("D", 641, "铜粉停吸时间");
        #endregion

        #region 压力表
        [Variable]
        public readonly Type水洗压力 SXYL水洗压力 = new Type水洗压力();
        #endregion

        #region  报警
        [Variable]
        public readonly Type报警 B报警 = new Type报警();
        #endregion

        #endregion

        #region MES配方
        
        #endregion

        /// <summary>
        /// Omron PLC IP地址, 默认地址: 192.168.1.1
        /// </summary>
        public string ip;

        /// <summary>
        /// Omron PLC 端口, 默认端口: 9600
        /// </summary>
        public int port;

        public Device device;

        /// <summary>
        /// PLC在线标志
        /// </summary>
        public bool Online;

        /// <summary>
        /// 数据轮询时间
        /// </summary>
        public TimeSpan CommTime { get; set; }

        public OmronData(string ip= "192.168.250.1", int port=9600)
        {
            this.ip = ip;
            this.port = port;

            var omron = new HslCommunication.Profinet.Omron.OmronFinsNet(this.ip, this.port);
            omron.ConnectTimeOut = 500; // ms
            omron.SetPersistentConnection();
            device = new Device(omron, 2);

            device.RegersterVariables(this);

            //Console.WriteLine("变量:");
            //foreach (var iter in device.Variables.Values)
            //{
            //    Console.WriteLine(iter.ToString());
            //}

            //Console.WriteLine("变量组:");
            //foreach (var iter in device.VariableGroups)
            //{
            //    Console.WriteLine(iter.Value.HslAddr);
            //}

            Console.WriteLine("孤立变量:");
            foreach (var iter in device.Variables.Values)
            {
                if (iter.Group == null)
                    Console.WriteLine(iter.ToString());
            }
        }

        public void SyncStart()
        {
            thread = new Thread(Deamon);
            thread.Start();
        }

        public void SyncStop()
        {
            Quit = true;
        }

        private Thread thread;

        private volatile bool Quit;

        /// <summary>
        /// PLC数据同步线程
        /// </summary>
        private void Deamon(object obj)
        {
            Quit = false;

            Online = false;
            bool LastOnline = false;

            RegisterLogVariables(this);

            RegisterPosedgeVariables(this);

            LoadAlarmCode();

            var T电流 = DateTime.Now;
            var T温度 = DateTime.Now;

            while (!Quit)
            {
                try
                {
                    var t = DateTime.Now;

                    device.Push();

                    var rpull = device.Pull();
                    if (rpull == null)
                    {
                        Online = true;
                    }
                    else
                    {
                        Online = false;
                        Console.WriteLine(rpull.ToMessageShowString());

                        continue;
                    }

                    // 通信时间测量
                    CommTime = DateTime.Now - t;

                    {   // 刚连线, 清除IsChanged信号
                        if (LastOnline != Online)
                        {
                            foreach (var iter in device.Variables.Values)
                            {
                                iter.ClearChanged();
                            }
                        }
                        LastOnline = Online;
                    }
                    ScanLogVariable();

                    ScanPosedgeVariables();

                    Check报警();

                    SaveCurrent(t, ref T电流);

                    SaveTemperature(t, ref T温度);
                }
                catch(Exception err)
                {
                    System.Windows.Forms.MessageBox.Show(err.Message + Environment.NewLine + err.StackTrace);
                    break;
                }
            }

            device.DisconnectServer();

        }

        /// <summary>
        /// 电流记录
        /// </summary>
        private void SaveCurrent(DateTime t, ref DateTime t0)
        {
            if ((t - t0).TotalMinutes >= 1)
            {
                t0 = t;

                var record = new CurrentRecordView()
                {
                    Time = t
                };
                for(int i=0; i<Config.镀铜槽数; i++)
                {
                    record.SlotCurrent[i].A[0] = this.D镀铜槽状态[i].C面实际电流[0].Value;
                

                    record.SlotCurrent[i].B[0] = this.D镀铜槽状态[i].S面实际电流[0].Value;
                 
                }

                CurrentRecordView.Add(record);
            }
        }

        /// <summary>
        /// 记录温度
        /// </summary>
        private void SaveTemperature(DateTime t, ref DateTime t0)
        {
            if ((t - t0).TotalMinutes >= 5)
            {
                t0 = t;

                var record = new TemperatureRecord
                {
                    Time = t,

                    除油温度 = this.CY除油温度.实际值.Value,
                    热水洗温度 = this.RS热水洗温度.实际值.Value,
                    整流机冷却 = this.ZL整流机冷却温度.实际值.Value,
                    酸洗槽 = this.SX酸洗槽温度.实际值.Value,
                    镀铜 = this.DT镀铜温度.实际值.Value,
                    微蚀 = this.WS微蚀温度.实际值.Value,
                    热水槽 = this.RS热水槽温度.实际值.Value,
                    烘干加热 = this.HG烘干加热温度.实际值.Value,
                    酸浸 = this.SJ酸浸温度.实际值.Value,
                    抗氧化 = this.KYH抗氧化槽温度.实际值.Value

    };
                TemperatureRecord.Add(record);
            }
        }

        #region 日志记录
        private class LogVariableType
        {
            public Variable variable;
            public string OperationType;
        }
        private Dictionary<string, LogVariableType> LogVariables;

        private void ScanLogVariable()
        {
            var user = Global.GetInstance().CurrentUser;
            if (user != null)
            {
                foreach (var iter in LogVariables.Values)
                {
                    var v = iter.variable;
                    var ot = iter.OperationType;

                    if (v.IsChanged)
                    {
                        v.ClearChanged();

                        var record = new OperationRecord
                        {
                            Time = DateTime.Now,
                            User = user.UserName,
                            Operation = v.ChangeMessage(),
                            OperationType = ot ?? "其他"
                        };
                        OperationRecord.Add(record);
                    }
                }
            }
        }

        /// <summary>
        /// 注册日志变量
        /// </summary>
        private void RegisterLogVariables(object obj)
        {
            LogVariables = new Dictionary<string, LogVariableType>();
            RegisterLogVariablesHelper(obj);

            Console.WriteLine("操作日志变量");
            foreach (var iter in LogVariables)
            {
                Console.WriteLine(iter.Value.variable.ToString());
            }
        }

        private void RegisterLogVariablesHelper(object obj)
        {
            var vars = obj.GetType().GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);

            foreach (var iter in vars)
            {
                var attr = iter.GetCustomAttribute<VariableLogAttribute>();
                if (attr != null)
                {
                    var value = iter.GetValue(obj);
                    var type = value.GetType();

                    if (value is Variable)
                    {
                        var v = iter.GetValue(obj) as Variable;
                        Debug.Assert(v != null);
                        LogVariables[v.HslAddr] = new LogVariableType() { variable = v, OperationType = attr.OperationType };
                    }
                    else if (type.IsArray)
                    {
                        var array = value as Array;

                        if (typeof(Variable).IsAssignableFrom(type.GetElementType()))
                        {
                            foreach (var it in array)
                            {
                                var tmp = it as Variable;
                                if (tmp.Addr > 0)
                                {
                                    Debug.Assert(!LogVariables.ContainsKey(tmp.HslAddr));
                                    LogVariables[tmp.HslAddr] = new LogVariableType() { variable = tmp, OperationType = attr.OperationType };
                                }
                            }
                        }
                        else
                        {   // 递归
                            foreach (var it in array)
                            {
                                RegisterLogVariablesHelper(it);
                            }
                        }
                    }
                    else if (type.IsGenericType && type is IEnumerable<object>)
                    {
                        var GAS = type.GetGenericArguments();
                        switch (GAS.Length)
                        {
                            case 1:
                                var list = value as IEnumerable<object>;

                                if (typeof(Variable).IsAssignableFrom(GAS[0].GetType()))
                                {
                                    foreach (var it in list)
                                    {
                                        var tmp = it as Variable;
                                        if (tmp.Addr > 0)
                                        {
                                            Debug.Assert(!LogVariables.ContainsKey(tmp.HslAddr));
                                            LogVariables[tmp.HslAddr] = new LogVariableType() { variable = tmp, OperationType = attr.OperationType };
                                        }
                                    }
                                }
                                else
                                {
                                    // 递归
                                    foreach (var it in list)
                                    {
                                        RegisterLogVariablesHelper(it);
                                    }
                                }
                                break;

                            case 2:
                                if (type is IDictionary<object, object>)
                                {
                                    var dict = value as IDictionary<object, object>;
                                    if (typeof(Variable).IsAssignableFrom(GAS[1].GetType()))
                                    {
                                        foreach (var it in dict)
                                        {
                                            var tmp = it.Value as Variable;
                                            if (tmp.Addr > 0)
                                            {
                                                Debug.Assert(!LogVariables.ContainsKey(tmp.HslAddr));
                                                LogVariables[tmp.HslAddr] = new LogVariableType() { variable = tmp, OperationType = attr.OperationType };
                                            }
                                        }
                                    }
                                    else
                                    {   // 递归
                                        foreach (var it in dict)
                                        {
                                             RegisterLogVariablesHelper(it.Value);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.Assert(false);
                                }
                                break;

                            default:
                                Debug.Assert(false);
                                break;
                        }
                    }
                    else if (type.IsClass)
                    {
                        RegisterLogVariablesHelper(value);
                    }

                    continue;
                }

                var attrv = iter.GetCustomAttribute<VariableAttribute>();
                if (attrv != null)
                {
                    var value = iter.GetValue(obj);
                    var type = value.GetType();

                    if (type.IsArray)
                    {
                        var array = value as Array;
                        // 递归
                        foreach (var it in array)
                        {
                            RegisterLogVariablesHelper(it);
                        }
                    }
                    else if (type.IsGenericType && type is IEnumerable<object>)
                    {
                        var GAS = type.GetGenericArguments();
                        switch (GAS.Length)
                        {
                            case 1:
                                var list = value as IEnumerable<object>;

                                // 递归
                                foreach (var it in list)
                                {
                                    RegisterLogVariablesHelper(it);
                                }
                                break;

                            case 2:
                                if (type is IDictionary<object, object>)
                                {
                                    var dict = value as IDictionary<object, object>;
                                    // 递归
                                    foreach (var it in dict)
                                    {
                                        RegisterLogVariablesHelper(it.Value);
                                    }
                                }
                                else
                                {
                                    Debug.Assert(false);
                                }
                                break;

                            default:
                                Debug.Assert(false);
                                break;
                        }
                    }
                    else if (type.IsClass)
                    {
                        RegisterLogVariablesHelper(value);
                    }
                }
            }
        }
        #endregion

        #region 故障检查
        public Dictionary<string, AlarmRecordView> AlarmDict { get; private set; }
        public Dictionary<string, AlarmCode> AlarmCodes { get; private set; }

        private void LoadAlarmCode()
        {
            AlarmDict = new Dictionary<string, AlarmRecordView>();

            AlarmCodes = new Dictionary<string, AlarmCode>();
            var list = AlarmCode.ListAll();
            foreach(var iter in list)
            {
                string key = "C" + iter.AbsAddr;
                AlarmCodes[key] = iter;
            }
        }

        private void Check报警()
        {
            // 检查新故障
            foreach (var iter in B报警.AlarmSet)
            {
                if (!iter.Value) continue;

                if (!AlarmDict.ContainsKey(iter.HslAddr))
                {
                    AlarmDict[iter.HslAddr] = new AlarmRecordView()
                    {
                        StartTime = DateTime.Now,
                        EndTime = DateTime.Now,

                        AlarmCodeId = AlarmCodes[iter.HslAddr].Id,
                        AlarmCode = AlarmCodes[iter.HslAddr]
                    };
                }
            }

            {   //处理消失故障
                var list = new List<string>();
                foreach (var iter in B报警.AlarmSet)
                {
                    if (iter.Value) continue;

                    if (AlarmDict.ContainsKey(iter.HslAddr))
                    {   // 字典中的故障消失, 计入故障列表
                        list.Add(iter.HslAddr);
                    }
                }

                if (list.Count > 0)
                {
                    using (var conn = AlarmRecordDBHelper.Open())
                    {
                        using (var trans = conn.BeginTransaction())
                        {
                            try
                            {
                                foreach (var key in list)
                                {
                                    var view = AlarmDict[key];
                                    view.EndTime = DateTime.Now;
                                    AlarmRecordView.Add(trans, view);
                                }

                                trans.Commit();
                            }
                            catch
                            {
                                trans.Rollback();
                            }
                        }
                    }

                    // 删除字典中的故障
                    foreach (var iter in list)
                    {
                        AlarmDict.Remove(iter);
                    }
                }
            }
        }
        #endregion

        #region 上升沿处理
        private class PosedgeVariableType
        {
            public Variable variable;
            public TimeSpan duration;
        }
        private Dictionary<string, PosedgeVariableType> PosedgeVariables;

        private Dictionary<string, DateTime> PosedgeVariableAbsTime;

        /// <summary>
        /// 注册上升沿变量
        /// </summary>
        private void RegisterPosedgeVariables(object obj)
        {
            PosedgeVariables = new Dictionary<string, PosedgeVariableType>();
            RegisterPosedgeVariablesHelper(obj);

            PosedgeVariableAbsTime = new Dictionary<string, DateTime>();

            Console.WriteLine("上升沿变量");
            foreach (var iter in PosedgeVariables)
            {
                Console.WriteLine(iter.Value.variable.ToString());
            }
        }

        private void RegisterPosedgeVariablesHelper(object obj)
        {
            var vars = obj.GetType().GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);

            foreach (var iter in vars)
            {
                var attr = iter.GetCustomAttribute<PosedgeAttribute>();
                if (attr != null)
                {
                    var value = iter.GetValue(obj);
                    var type = value.GetType();

                    if (value is Variable)
                    {
                        var v = iter.GetValue(obj) as Variable;
                        if (v.Addr > 0)
                        {
                            Debug.Assert(!PosedgeVariables.ContainsKey(v.HslAddr));
                            PosedgeVariables[v.HslAddr] = new PosedgeVariableType() { variable = v, duration = attr.Duration };
                        }
                    }
                    else if (type.IsArray)
                    {
                        var array = value as Array;

                        if (typeof(Variable).IsAssignableFrom(type.GetElementType()))
                        {
                            foreach (var it in array)
                            {
                                var tmp = it as Variable;
                                if (tmp.Addr > 0)
                                {
                                    Debug.Assert(!PosedgeVariables.ContainsKey(tmp.HslAddr));
                                    PosedgeVariables[tmp.HslAddr] = new PosedgeVariableType() { variable = tmp, duration = attr.Duration };
                                }
                            }
                        }
                        else
                        {   // 递归
                            foreach (var it in array)
                            {
                                RegisterPosedgeVariablesHelper(it);
                            }
                        }
                    }
                    else if (type.IsGenericType && type is IEnumerable<object>)
                    {
                        var GAS = type.GetGenericArguments();
                        switch (GAS.Length)
                        {
                            case 1:
                                var list = value as IEnumerable<object>;

                                if (typeof(Variable).IsAssignableFrom(GAS[0].GetType()))
                                {
                                    foreach (var it in list)
                                    {
                                        var tmp = it as Variable;
                                        if (tmp.Addr > 0)
                                        {
                                            Debug.Assert(!PosedgeVariables.ContainsKey(tmp.HslAddr));
                                            PosedgeVariables[tmp.HslAddr] = new PosedgeVariableType() { variable = tmp, duration = attr.Duration };
                                        }
                                    }
                                }
                                else
                                {
                                    // 递归
                                    foreach (var it in list)
                                    {
                                        RegisterPosedgeVariablesHelper(it);
                                    }
                                }
                                break;

                            case 2:
                                if (type is IDictionary<object, object>)
                                {
                                    var dict = value as IDictionary<object, object>;
                                    if (typeof(Variable).IsAssignableFrom(GAS[1].GetType()))
                                    {
                                        foreach (var it in dict)
                                        {
                                            var tmp = it.Value as Variable;
                                            if (tmp.Addr > 0)
                                            {
                                                Debug.Assert(!PosedgeVariables.ContainsKey(tmp.HslAddr));
                                                PosedgeVariables[tmp.HslAddr] = new PosedgeVariableType() { variable = tmp, duration = attr.Duration };
                                            }
                                        }
                                    }
                                    else
                                    {   // 递归
                                        foreach (var it in dict)
                                        {
                                            RegisterPosedgeVariablesHelper(it.Value);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.Assert(false);
                                }
                                break;

                            default:
                                Debug.Assert(false);
                                break;
                        }
                    }
                    else if (type.IsClass)
                    {
                        RegisterPosedgeVariablesHelper(value);
                    }
                    continue;
                }

                var attrv = iter.GetCustomAttribute<VariableAttribute>();
                if (attrv != null)
                {
                    var value = iter.GetValue(obj);
                    var type = value.GetType();

                    if (type.IsArray)
                    {
                        var array = value as Array;
                        // 递归
                        foreach (var it in array)
                        {
                            RegisterPosedgeVariablesHelper(it);
                        }
                    }
                    else if (type.IsGenericType && type is IEnumerable<object>)
                    {
                        var GAS = type.GetGenericArguments();
                        switch (GAS.Length)
                        {
                            case 1:
                                var list = value as IEnumerable<object>;

                                // 递归
                                foreach (var it in list)
                                {
                                    RegisterPosedgeVariablesHelper(it);
                                }
                                break;

                            case 2:
                                if (type is IDictionary<object, object>)
                                {
                                    var dict = value as IDictionary<object, object>;
                                    // 递归
                                    foreach (var it in dict)
                                    {
                                        RegisterPosedgeVariablesHelper(it.Value);
                                    }
                                }
                                else
                                {
                                    Debug.Assert(false);
                                }
                                break;

                            default:
                                Debug.Assert(false);
                                break;
                        }
                    }
                    else if (type.IsClass)
                    {
                        RegisterPosedgeVariablesHelper(value);
                    }
                    continue;
                }
            }
        }

        private void ScanPosedgeVariables()
        {
            var now = DateTime.Now;

            foreach(var iter in PosedgeVariables.Values)
            {
                string key = iter.variable.HslAddr;

                if (iter.variable.IsTrue())
                {   // ON
                    if (PosedgeVariableAbsTime.ContainsKey(key))
                    {   
                        if (now > PosedgeVariableAbsTime[key])
                        {   // ON -> OFF
                            iter.variable.SetFalse();
                        }
                    }
                    else
                    {   // OFF -> ON
                        PosedgeVariableAbsTime[key] = now + iter.duration;
                    }
                }
                else
                {   // OFF 删除记录
                    if (PosedgeVariableAbsTime.ContainsKey(key))
                    {
                        PosedgeVariableAbsTime.Remove(key);
                    }
                }
            }
        }
        #endregion
    }

    internal static class Extersion
    {
        public static bool IsTrue(this Variable value)
        {
            var property = value.GetType().GetProperty("RawValue");
            if (property == null) return false;

            var RawValue = property.GetValue(value);
            switch (RawValue)
            {
                case bool tmp: return tmp;
                case Int16 tmp: return tmp != 0;
                case UInt16 tmp: return tmp != 0;
                case Int32 tmp: return tmp != 0;
                case UInt32 tmp: return tmp != 0;
                case Int64 tmp: return tmp != 0;
                case UInt64 tmp: return tmp != 0;
                case float tmp: return tmp != 0;
                case double tmp: return tmp != 0;

                default: return false;
            }
        }

        public static bool IsFalse(this Variable value)
        {
            return !value.IsTrue();
        }

        public static void SetFalse(this Variable value)
        {
            var property = value.GetType().GetProperty("RawValue");
            if (property == null) return;

            if (property.PropertyType == typeof(bool))
                property.SetValue(value, false, null);
            else
                property.SetValue(value, 0, null);

        }
    }
    

    /// <summary>
    /// 变量日志修饰
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    public class VariableLogAttribute: Attribute
    {
        public VariableLogAttribute()
        {
        }

        /// <summary>
        /// 操作类型
        /// </summary>
        public string OperationType { get; set; } 
    }

    /// <summary>
    /// 上升沿修饰修饰
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    public class PosedgeAttribute : Attribute
    {
        public PosedgeAttribute(int ms=10)
        {
            Duration = new TimeSpan(0, 0, 0, 0, ms);
        }

        /// <summary>
        /// 高电平持续时间
        /// </summary>
        public TimeSpan Duration { get; set; }
    }
}
